﻿using JinianNet.JNTemplate;
using JinianNet.JNTemplate.Caching;
using Mapster;
using MapsterMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using My.Core.Attributes;
using My.Core.CustomException;
using My.Core.Filters;
using My.Core.Helper;
using My.Core.Options;
using My.Core.Quartz.Extension;
using My.Core.SqlSugar;
using My.Core.Util;
using My.Framework.AspNetCore;
using NewLife.Caching;
using NLog;
using NLog.Web;
using Savorboard.CAP.InMemoryMessageQueue;
using System.IO;
using System.Text.Json;

namespace My.Core.Startup
{
    /// <summary>
    /// 基础启动器
    /// </summary>
    /// <typeparam name="TStartupMoudle"></typeparam>

    public class AppStartupBaseCore<TStartupMoudle> : StartupModule<TStartupMoudle> where TStartupMoudle : IStartupModule, new()
    {
        /// <summary>
        /// 基础启动器
        /// </summary>
        public AppStartupBaseCore() => Order = 0;

		/// <summary>
		/// 配置服务
		/// </summary>
		/// <param name="webApplicationBuilder"></param>
		public override void ConfigureServices(WebApplicationBuilder webApplicationBuilder)
        {
            var services = webApplicationBuilder.Services;
            //services.AddControllers();
            webApplicationBuilder.Host.UseNLog();

            Logger logger = LogManager.GetCurrentClassLogger();
            logger.Info("项目启动");

			//禁用默认行为
			services.Configure<ApiBehaviorOptions>(options =>
			{
				// 禁用默认模型验证过滤器
				options.SuppressModelStateInvalidFilter = true;
			});

			services.AddControllers(options =>
			{
				options.Filters.Add(typeof(DataValidationFilter));			// 全局注册,自定义模型验证过滤器
				options.Filters.Add(typeof(LogAttributeFilter));           // 全局注册,操作日志过滤
				options.Filters.Add(typeof(LoggingMonitorAttribute));		// 全局注册,将请求的信息打印出来
			}).AddJsonOptions(options =>
			{
				//options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString;
				options.JsonSerializerOptions.WriteIndented = true;
				options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeConverter());
				options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeNullConverter());
				options.JsonSerializerOptions.Converters.Add(new StringConverter());
				//PropertyNamingPolicy属性用于前端传过来的属性的格式策略，目前内置的仅有一种策略CamelCase
				options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
				//options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;//属性可以忽略大小写格式，开启后性能会降低
			});

			//绑定整个对象到Model上
			services.Configure<OptionsSetting>(webApplicationBuilder.Configuration);
			//webApplicationBuilder.Configuration.AddJsonFile("iprate.json");
			
			services.AddOptions<JwtSettings>().Bind(webApplicationBuilder.Configuration.GetSection("JwtSettings"), options =>
			{
				options.BindNonPublicProperties = true; // 绑定私有变量
			}).ValidateDataAnnotations();
			services.AddOptions<SnowIdSetting>().Bind(webApplicationBuilder.Configuration.GetSection("SnowIdSetting"), options =>
			{
				options.BindNonPublicProperties = true; // 绑定私有变量
			}).ValidateDataAnnotations();
			services.AddSingleton(new AppSettings(webApplicationBuilder.Configuration));

			// 获取全局映射配置
			var config = TypeAdapterConfig.GlobalSettings;

			if (AssemblyUtil.GetAssemblyList().ToList() == null) return;
			var assemblies = AssemblyUtil.GetAssemblyList().ToArray();

			// 扫描所有继承  IRegister 接口的对象映射配置
			if (assemblies != null && assemblies.Length > 0) config.Scan(assemblies);

			// 配置默认全局映射（支持覆盖）
			config.Default
				  .NameMatchingStrategy(NameMatchingStrategy.Flexible)
				  .PreserveReference(true);

			// 配置默认全局映射（忽略大小写敏感）
			config.Default
				  .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase)
				  .PreserveReference(true);

			// 配置支持依赖注入
			services.AddSingleton(config);
			services.AddScoped<IMapper, ServiceMapper>();

			webApplicationBuilder.Configuration.AddInMemoryCollection();

			// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
			services.AddEndpointsApiExplorer();

            //注入HttpContextAccessor
            services.AddHttpContextAccessor();

            //消除Error unprotecting the session cookie警告
            services.AddDataProtection()
                .PersistKeysToFileSystem(new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "DataProtection"));

			// 添加内存缓存
			services.AddMemoryCache();

			// 注册REDIS 服务
			NewLife.Caching.ICache cache = NewLife.Caching.Cache.Default;
			cache = new FullRedis(new RedisOptions
			{
				Configuration = AppSettings.GetConfig("Redis:Configuration"),
				Prefix = "admin"
			});
			services.AddSingleton(cache);

			// 验证码
			services.AddCaptcha(webApplicationBuilder.Configuration);

			// 注册CAP
			services.AddCap(x =>
			{
				x.UseInMemoryStorage();
				x.UseInMemoryMessageQueue();
			});
		}

		/// <summary>
		/// 配置
		/// </summary>
		/// <param name="webApplication"></param>
		public override void Configure(WebApplication webApplication)
        {
			//使用全局异常中间件
			webApplication.UseMiddleware<GlobalExceptionMiddleware>();

			webApplication.UseHttpsRedirection();

			//请求头转发
			//ForwardedHeaders中间件会自动把反向代理服务器转发过来的X-Forwarded-For（客户端真实IP）以及X-Forwarded-Proto（客户端请求的协议）自动填充到HttpContext.Connection.RemoteIPAddress和HttpContext.Request.Scheme中，这样应用代码中读取到的就是真实的IP和真实的协议了，不需要应用做特殊处理。
			webApplication.UseForwardedHeaders(new ForwardedHeadersOptions
			{
				ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
			});

			//开启访问静态文件/wwwroot目录文件，要放在UseRouting前面
			webApplication.UseStaticFiles();

			//webApplication.MapControllers();
        }

		/// <summary>
		/// 程序启动 可以获取程序启动 urls
		/// </summary>
		/// <param name="webApplication"></param>
		public override void ApplicationStarted(WebApplication webApplication)
        {
			// 初始化db
			SqlSugarExtension.AddDb();

			// logo显示
			Console.ForegroundColor = ConsoleColor.Blue;
			var contentTpl = JnHelper.ReadTemplate("", "logo.txt");
			var content = contentTpl?.Render();
			Console.WriteLine(content);

			// 初始化定时任务
			JobTasksExtension.AddJobTasks();
		}

		/// <summary>
		/// 程序停止中
		/// </summary>
		/// <param name="webApplication"></param>
		public override void ApplicationStopping(WebApplication webApplication)
        { }

		/// <summary>
		/// 程序已经停止
		/// </summary>
		/// <param name="webApplication"></param>
		public override void ApplicationStopped(WebApplication webApplication)
        { }

    }
}
